﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Super_Wall_Breaker.Sources.TeamElements.PlayersControls;
using Super_Wall_Breaker.Sources.GameEngine;
using Super_Wall_Breaker.Sources.TeamElements.Players;
using Super_Wall_Breaker.Sources.TeamElements;
using Super_Wall_Breaker.Sources.GameElements.Balls;

namespace Super_Wall_Breaker.Sources.Factories
{
    /// <summary>
    /// This class creates Player instances.
    /// </summary>
    public static class PlayerFactory
    {
        /// <summary>
        /// This function creates an AI player.
        /// </summary>
        /// <param name="playerIndex">The index of the player.</param>
        /// <param name="balls">The list of balls in the game, used to calculates IA deplacement.</param>
        /// <param name="speed">The speed of the player batt.</param>
        /// <returns>The AI player created.</returns>
        public static AIPlayer CreateAIPlayer(PlayerIndex playerIndex, List<Ball> balls, Vector2 speed)
        {
            return (AIPlayer)PlayerFactory.CreatePlayer(playerIndex, null, balls, speed);
        }

        /// <summary>
        /// This function creates a human player.
        /// </summary>
        /// <param name="playerIndex">The index of the player.</param>
        /// <param name="controls"> The controls type of the player.</param>
        /// <param name="speed">The speed of the bat.</param>
        /// <returns>An human player.</returns>
        public static RealPlayer CreateRealPlayer(PlayerIndex playerIndex, ControlsType controls, Vector2 speed)
        {
            return (RealPlayer)PlayerFactory.CreatePlayer(playerIndex, controls, null, speed);
        }


        /// <summary>
        /// This function creates a player instance.
        /// </summary>
        /// <param name="playerIndex">The index of the player.</param>
        /// <param name="controls">The controls of the player, set null to create an AI player.</param>
        /// <param name="balls">The list of the balls, used to create an AI, null for real player.</param>
        /// <param name="speed">The speed of the bat.</param>
        /// <returns>A Player, RealPlayer or AIPlayer instance</returns>
        private static Player CreatePlayer(PlayerIndex playerIndex, ControlsType? controls, List<Ball> balls, Vector2 speed)
        {
            GlobalConfiguration config = GlobalConfiguration.Configuration; // The configuration instance

            Rectangle playerBatTexture = new Rectangle(0, 17, 126, 16); // The rectangle to select in the sprite sheet.

            int yPosition = 0;
            int xPosition = (config.ScreenWidth - playerBatTexture.Width) / 2;
            
            TeamIndex teamIndex = TeamIndex.top;

            PlayerIndex gamePadIndex = playerIndex;

            if(controls.Equals(ControlsType.GAMEPAD))
                gamePadIndex = PlayerFactory.GetGamePadIndex();  // This player index is usefull to know the gamepad number of a player, the first player index (in args) is used to know the place and the team of a player.
            // We have to use a different player index because, for example, if the two first players play with the keyboard, and the third with a gamepad, the gamepad used have to be the number one.

            switch (playerIndex)
            {
                case PlayerIndex.One: // Player 1 : Team = Bottom, Player position = Top
                    yPosition = config.ScreenHeight - 2 * (GlobalConfiguration.DEFAULT_BAT_SPACING + playerBatTexture.Height); 
                    teamIndex = TeamIndex.bottom;
                    break;

                case PlayerIndex.Two: // Player 2 : Team = Top, Player position = Bottom
                    yPosition = 2 * GlobalConfiguration.DEFAULT_BAT_SPACING + playerBatTexture.Height;
                    break;

                case PlayerIndex.Three: // Player 3 : Team = Bottom, Player position = Bottom
                    yPosition = config.ScreenHeight - (GlobalConfiguration.DEFAULT_BAT_SPACING + playerBatTexture.Height); 
                    teamIndex = TeamIndex.bottom;
                    break;

                case PlayerIndex.Four: // Player 4 : Team = Top, Player position = Top
                    yPosition = GlobalConfiguration.DEFAULT_BAT_SPACING; 
                    break;                    
            }

            Vector2 playerBatPosition = new Vector2(xPosition, yPosition);

            Player player;

            if (controls == null) // AI case
            {
                player = new AIPlayer(balls, teamIndex, playerBatPosition, speed, playerBatTexture);
            }
            else
            {
                if(controls.Equals(ControlsType.GAMEPAD)) // GamePad used
                    player = new RealPlayer(teamIndex, gamePadIndex, (ControlsType)controls, playerBatPosition, speed, playerBatTexture);
                else//Keyboard
                    player = new RealPlayer(teamIndex, playerIndex, (ControlsType)controls, playerBatPosition, speed, playerBatTexture);
            }

            player.Bat.Color = TeamsFactory.GetTeamColor(teamIndex);

            return player;
        }

        /// <summary>
        ///  This function returns the gamepad index to used, ie the first gamepad unused.
        /// </summary>
        /// <returns>The gamepad index to use.</returns>
        public static PlayerIndex GetGamePadIndex()
        {
            GlobalConfiguration config = GlobalConfiguration.Configuration;
            PlayerIndex returnedIndex;
            
            if (!config.GamePadOneIsUsed)
            {
                returnedIndex = PlayerIndex.One;
                config.GamePadOneIsUsed = true;
            }
            else if (!config.GamePadTwoIsUsed)
            {
                returnedIndex = PlayerIndex.Two;
                config.GamePadTwoIsUsed = true;
            }
            else if (!config.GamePadThreeIsUsed)
            {
                returnedIndex = PlayerIndex.Three;
                config.GamePadThreeIsUsed = true;
            }
            else
            {
                returnedIndex = PlayerIndex.Four;
                config.GamePadFourIsUsed = true;
            }            

            return returnedIndex;
        }
    }
}
